GitHub GraphQL APIでProjectにIssuesを追加して、フィールドを更新する(Estimate, Status)
GitHub GraphQL APIでProjectにIssuesを追加してみました。 そのあと、EstimateとStatusとを設定してみます。
おすすめの方
- GitHub GraphQL APIについて知りたい方
- GitHub GraphQL APIでProjectにIssuesを追加したい方
- GitHub GraphQL APIでProjectのItemのフィールドを取得・更新したい方
- GitHub GraphQL APIで変数を使いたい方
GitHub Projectのフィールド
デフォルトのフィールドを利用します。
GitHub GraphQL APIでProjectにIssuesを追加するスクリプト
プロジェクト番号は、URLに含まれています。たとえば、「projects/4/views/1」なら、プロジェクト番号は「4」です。
また、プロジェクトが「User or Organization」のどちらにあるかによって、GraphQLのクエリ内容が異なります。 次のコードでは両方記載しています。
import requests import json from enum import StrEnum ENDPOINT = "https://api.github.com/graphql" GITHUB_TOKEN = "xxx" GITHUB_REPOSITORY_OWNER = "yyy" GITHUB_REPOSITORY_NAME = "zzz" GITHUB_PROJECT_NUMBER = 4 class StatusName(StrEnum): TODO = "Todo" IN_PROGRESS = "In Progress" DONE = "Done" def main(): # リポジトリIDを取得する repository_id = get_repository_id(GITHUB_REPOSITORY_OWNER, GITHUB_REPOSITORY_NAME) # プロジェクト情報を取得する(User) project_id, project_fields = get_project_v2_user( GITHUB_REPOSITORY_OWNER, GITHUB_PROJECT_NUMBER ) # プロジェクト情報を取得する(Organization) # project_id, project_fields = get_project_v2_organization(GITHUB_REPOSITORY_OWNER, GITHUB_PROJECT_NUMBER) # プロジェクトのフィールドIDとオプションIDを取得する for item in project_fields: if item.get("name", "") == "Estimate": estimate_id = item["id"] if item.get("name", "") == "Status": status_id = item["id"] status_options = array_to_dict(item["options"], "name") # Issueを作成する issue_id = create_issue( repository_id, "これがタイトルです", "これが本文です", ) # Issueをプロジェクトに追加する project_item_id = add_issue_to_project(project_id, issue_id) # Estimateを更新する update_project_v2_item_field_number(project_id, project_item_id, estimate_id, 3) # Statusを更新する update_project_v2_item_field_single_select_option_id( project_id, project_item_id, status_id, status_options[StatusName.TODO]["id"] ) def get_repository_id( repository_owner, repository_name, ): query = """ query getProjectLabels($repositoryOwner:String!, $repositoryName:String!) { repository(owner: $repositoryOwner, name: $repositoryName) { id } } """ variables = { "repositoryOwner": repository_owner, "repositoryName": repository_name, } resp = requests.post( ENDPOINT, headers=get_headers(), data=json.dumps({"query": query, "variables": variables}), ) body = resp.json() return body["data"]["repository"]["id"] def get_project_v2_user( repository_owner, number, ): query = """ query getProjectV2($repositoryOwner:String!, $number:Int!) { user(login: $repositoryOwner){ projectV2(number: $number) { id, fields(first: 20) { nodes { ... on ProjectV2Field { id name } ... on ProjectV2SingleSelectField { id name options { id name } } } } } } } """ variables = { "repositoryOwner": repository_owner, "number": number, } resp = requests.post( ENDPOINT, headers=get_headers(), data=json.dumps({"query": query, "variables": variables}), ) body = resp.json() return ( body["data"]["user"]["projectV2"]["id"], body["data"]["user"]["projectV2"]["fields"]["nodes"], ) def get_project_v2_organization( repository_owner, number, ): query = """ query getProjectV2($repositoryOwner:String!, $number:Int!) { organization(login: $repositoryOwner){ projectV2(number: $number) { id, fields(first: 20) { nodes { ... on ProjectV2Field { id name } ... on ProjectV2SingleSelectField { id name options { id name } } } } } } } """ variables = { "repositoryOwner": repository_owner, "number": number, } resp = requests.post( ENDPOINT, headers=get_headers(), data=json.dumps({"query": query, "variables": variables}), ) body = resp.json() return ( body["data"]["organization"]["projectV2"]["id"], body["data"]["organization"]["projectV2"]["fields"]["nodes"], ) def create_issue(repository_id, title, body, labels=[]): mutation = """ mutation CreateIssue($repositoryId: ID!, $title: String!, $body: String, $labelIds: [ID!]) { createIssue(input: {repositoryId: $repositoryId, title: $title, body: $body, labelIds: $labelIds}) { issue { id number title bodyText } } } """ variables = { "repositoryId": repository_id, "title": title, "body": body, "labelIds": labels, } resp = requests.post( ENDPOINT, headers=get_headers(), data=json.dumps({"query": mutation, "variables": variables}), ) body = resp.json() return body["data"]["createIssue"]["issue"]["id"] def add_issue_to_project(project_id, issue_id): mutation = """ mutation AddIssueToProject($projectId: ID!, $contentId: ID!) { addProjectV2ItemById(input: {projectId: $projectId, contentId: $contentId}) { item { id } } }""" variables = { "projectId": project_id, "contentId": issue_id, } resp = requests.post( ENDPOINT, headers=get_headers(), data=json.dumps({"query": mutation, "variables": variables}), ) body = resp.json() return body["data"]["addProjectV2ItemById"]["item"]["id"] def update_project_v2_item_field_single_select_option_id( project_id, item_id, field_id, value ): mutation = """ mutation updateProjectV2ItemFieldValue($projectId: ID!, $itemId: ID!, $fieldId: ID!, $value: String) { updateProjectV2ItemFieldValue(input: {projectId: $projectId, itemId: $itemId, fieldId: $fieldId, value: {singleSelectOptionId: $value}}) { projectV2Item { id } } }""" variables = { "projectId": project_id, "itemId": item_id, "fieldId": field_id, "value": value, } resp = requests.post( ENDPOINT, headers=get_headers(), data=json.dumps({"query": mutation, "variables": variables}), ) body = resp.json() def update_project_v2_item_field_number(project_id, item_id, field_id, value): mutation = """ mutation updateProjectV2ItemFieldValue($projectId: ID!, $itemId: ID!, $fieldId: ID!, $value: Float) { updateProjectV2ItemFieldValue(input: {projectId: $projectId, itemId: $itemId, fieldId: $fieldId, value: {number: $value}}) { projectV2Item { id } } }""" variables = { "projectId": project_id, "itemId": item_id, "fieldId": field_id, "value": value, } resp = requests.post( ENDPOINT, headers=get_headers(), data=json.dumps({"query": mutation, "variables": variables}), ) body = resp.json() def get_headers(): return { "Authorization": f"bearer {GITHUB_TOKEN}", "Accept": "application/vnd.github.bane-preview+json", } def array_to_dict(array: list, key_name: str): return {x[key_name]: x for x in array} if __name__ == "__main__": main()
実行結果
python app.py
GitHub ProjectにIssuesが追加されました。 StatusとEstimateも設定されています。
Issues側でも確認できます。
さいごに
GitHub GraphQL APIでProjectにIssuesを追加して、フィールドを更新してみました。 フィールド情報を取得してフィールドIDを特定してから更新するのが少し手間かもしれません。 参考になれば幸いです。